/*
 * main.cpp
 *
 *  Created on: Nov 9, 2012
 *      Author: bannok
 */

#include<stdlib.h>
#include<stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <string>
#include <time.h>
#include "g2p_dsearch.h"
#include "g2p_syllable_tree.h"
#include "g2p_pronun_struct.h"
#include "g2p_ngram.h"
#include "g2p_tone_gram.h"
#include "config.h"
#include "g2p_close_match.h"
#include "g2p_syllable_map.h"
#include "debug.h"
#include "segment/ws_segment.h"
#include "g2p_syllable_extract.h"
Darts::DoubleArray esan_da;


char * test_sequence(char * txt, syllable_seq * seq,int * fxn);
//syllable_prob_bundle * tab_max = NULL;
//syllable_maximum_pair * max_pair;
char *replace(char *st, char *orig, char *repl) {
	if (st == NULL)
		return NULL;
	char *buffer = (char *) calloc(512 + 1, sizeof(char));
	char *ch;

	if (!(ch = strstr(st, orig))) {
		strcpy(buffer, st);
		return buffer;
	}
	return buffer;
}
char * removeToneSymbol(char * text) {
	//char * t1 = replace(text,"่","");
	char * t2 = replace(text, "้", "");
	//char * t3 = replace(t2,"๊","");
	//char * t4 = replace(t3,"๋","");
//printf("\n%s %s %s %s",t1,t2,t3,t4);
	//free(t1);
	//free(t2);
	//free(t3);
	return t2;
}
int skip(char * text, int index) {
	int len = strlen(text);
	if (len >= index) {

		if (text[index] >= (signed char) 0xb0
				&& text[index] <= (signed char) 0xba) {
			return 0;
		} else if (text[index] == (signed char) 0x88
				&& text[index - 1] == (signed char) 0xb9) {
			return 1;
		} else if (text[index] == (signed char) 0x89
				&& text[index - 1] == (signed char) 0xb9) {
			return 2;
		} else if (text[index] == (signed char) 0x8a
				&& text[index - 1] == (signed char) 0xb9) {
			return 3;
		} else if (text[index] == (signed char) 0x8b
				&& text[index - 1] == (signed char) 0xb9) {
			return 4;
		} else if (text[index] == (signed char) 0x8c
				|| text[index] == (signed char) 0x8d
				|| text[index] == (signed char) 0x8e) {
			return 0;
		}
	}
	return -1;

}
float parent_child_prob(pronun_struct_unit *p_st, pronun_struct_unit *c_st) {
	char tmp1[50], tmp2[50];
	float p = 0;
	if (c_st->sound == 2) {
		sprintf(tmp1, "%06d", c_st->st1);
		sprintf(tmp1, "%06d", c_st->st2);
		p += ngram_calculate(tmp1, tmp2);
	}
	if (p_st->sound == 2)
		sprintf(tmp1, "%06d", p_st->st2);
	else
		sprintf(tmp1, "%06d", p_st->st1);
	sprintf(tmp2, "%06d", c_st->st1);
	p += ngram_calculate(tmp1, tmp2);
	return p;
}
void print_prob_table(syllable_node * current) {
	if (current->prob_tab != NULL) {
		syllable_prob_table ** tmp = current->prob_tab;
		int size = current->prob_tab_row;
		printf("\n-----------------------------------------------------------");
		printf(
				"\n|\tParent\t|\tcChild\t|\tpar_id\t|\tpst_id\t|\tcst_id\t|\tprob\t|");
		printf("\n-----------------------------------------------------------");
		for (int i = 0; i < size; i++) {
			printf("\n|%p\t|%p\t|\t%d\t|\t%d\t|\t%d\t|\t%.4f\t|",
					tmp[i]->parent, tmp[i]->child, tmp[i]->par_id,
					tmp[i]->pst_id, tmp[i]->cst_id, tmp[i]->prob);
		}
	}
}
/*
 void free_max_pair() {
 if (max_pair != NULL) {
 if (max_pair->unit != NULL)
 free(max_pair->unit);
 }
 free(max_pair);
 }*/
/*
 * compare current maximum probability with new sequence
 */
void check_max_prob(syllable_prob_bundle * tab_max,
		syllable_prob_bundle * new_table) {

	if (tab_max->size == 0) {
		for (int i = 0; i < new_table->size; i++) {
			tab_max->prob_chain[i] = new_table->prob_chain[i];
		}
		tab_max->size = new_table->size;
		tab_max->prob = new_table->prob;
	} else if (tab_max->prob < new_table->prob) {
		for (int i = 0; i < new_table->size; i++) {
			tab_max->prob_chain[i] = new_table->prob_chain[i];
		}
		tab_max->size = new_table->size;
		tab_max->prob = new_table->prob;
	}
	free(new_table);

}
void leaf2root(syllable_node * current, syllable_node * root,
		syllable_stack_tab * stack_table) {
	for (int i = 0; i < current->parent_size; i++) {
		//printf("\n#[%p %s]-->[%p %s] (%d)", current, current->text,
		//		current->parent[i], current->parent[i]->text,
		//		current->parent_size);

		//test cross structure
		if (current->parent[i] != root && !current->cal_prob) {
			if (current->prob_tab == NULL) {
				//current->prob_tab = syllable_create_prob_table(current,
				//		SYLLABLE_PROB_SIZE);
			}
			int amount_unit = current->parent[i]->struc->st_unit;
			//printf("\nPunit : %d", amount_unit);
			for (int j = 0; j < amount_unit; j++) {

				for (int k = 0; k < current->struc->st_unit; k++) {

					//add leaf prob
					float prob = 0;
					if (current->child_size == 0) {
						char tmp[20];
						if (current->struc->st[k]->sound == 2) {
							sprintf(tmp, "%06d", current->struc->st[k]->st2);
						} else {
							sprintf(tmp, "%06d", current->struc->st[k]->st1);
						}
						prob = ngram_calculate(tmp, "E");
						//printf("\nEND prob = %.4f", prob);

					}
					/*printf("\n\tP(%06d:%06d|%06d:%06d) = %.4f",
					 current->parent[i]->struc->st[j]->st1,
					 current->parent[i]->struc->st[j]->st2,
					 current->struc->st[k]->st1,
					 current->struc->st[k]->st2,
					 parent_child_prob(current->parent[i]->struc->st[j],
					 current->struc->st[k]));*/
					syllable_prob_table * pset = (syllable_prob_table *) malloc(
							sizeof(syllable_prob_table));
					pset->par_id = i;
					pset->pst_id = j;
					pset->cst_id = k;
					pset->prob = prob
							+ parent_child_prob(
									current->parent[i]->struc->st[j],
									current->struc->st[k]);
					pset->child = current;
					pset->parent = current->parent[i];
					current->prob_tab[current->prob_tab_row++] = pset;
					stack_table->element[stack_table->size++] = pset;
					//clone bundle

				}

			}

		}
		if (current->parent[i] == root && !current->cal_prob) {
			if (current->prob_tab == NULL) {
				//current->prob_tab = (syllable_prob_table **) calloc(10,
				//		sizeof(syllable_prob_table *));
				current->prob_tab_row = 0;
				current->prob_tab_max = 10;
			}

			for (int k = 0; k < current->struc->st_unit; k++) {
				float firstp = 0;
				char tmp1[50], tmp2[50];
				float prob = 0;
				if (current->child_size == 0) {
					char tmp[20];
					if (current->struc->st[k]->sound == 2) {
						sprintf(tmp, "%06d", current->struc->st[k]->st2);
					} else {
						sprintf(tmp, "%06d", current->struc->st[k]->st1);
					}
					prob = ngram_calculate(tmp, "E");
				}
				if (current->struc->st[k]->sound == 2) {
					sprintf(tmp1, "%06d", current->struc->st[k]->st1);
					sprintf(tmp2, "%06d", current->struc->st[k]->st2);
					firstp += ngram_calculate(tmp1, tmp2);
				}
				sprintf(tmp2, "%06d", current->struc->st[k]->st1);
				sprintf(tmp1, "B");
				firstp += ngram_calculate(tmp1, tmp2) + prob;

				//printf("\n\tP(%06d:%06d|B) = %.4f", current->struc->st[k]->st1,
				//		current->struc->st[k]->st2, firstp);
				syllable_prob_table * pset = (syllable_prob_table *) malloc(
						sizeof(syllable_prob_table));
				pset->par_id = 0;
				pset->pst_id = 0;
				pset->cst_id = k;
				pset->prob = firstp;
				pset->child = current;
				pset->parent = root;
				current->prob_tab[current->prob_tab_row++] = pset;
				stack_table->element[stack_table->size++] = pset;
			}

		}
		//pronun_struct_print(current->parent[i]->struc);
	}
	//print_prob_table(current);
	current->cal_prob = true;
	for (int i = 0; i < current->parent_size; i++) {
		leaf2root(current->parent[i], root, stack_table);
	}
}
void route2root(syllable_node * current, syllable_node * root,
		syllable_prob_bundle * p_bundle, syllable_prob_bundle * max_bundle) {

	bool clone = false;
	//printf("current %p root %p", current, root);
	if (current->prob_tab_row != 0) {
		int parent_size = current->parent_size;
		//printf("\nCURR = %s", current->text);
		for (int i = 0; i < parent_size; i++) {
			syllable_node * curr_parent = current->parent[i];
			for (int j = 0; j < current->prob_tab_row; j++) {
				//go to parent node
				//printf("\nP[%s] %s ", current->parent[i]->text,
				//		current->prob_tab[j]->parent->text);
				if (current->prob_tab[j]->parent == curr_parent) {
					//printf("\n--> %s", current->text);
					syllable_prob_bundle * p = syllable_clone_prob_bundle(
							p_bundle);

					p->prob_chain[p->size] = current->prob_tab[j];
					p->prob = p_bundle->prob + current->prob_tab[j]->prob;
					p->size++;
					clone = true;
					route2root(current->parent[i], root, p, max_bundle);

				}
			}

		}
		if (clone == true && p_bundle != max_bundle) {
			free(p_bundle);
		}
	} else if (current == root) {
		//printf("\n[%p] %s", current, current->text);
		//printf("\n[%p] %.4f", p_bundle, p_bundle->prob);
		syllable_prob_bundle_print(p_bundle, stdout);
		check_max_prob(max_bundle, p_bundle);
	}

}
void backwordConcat(syllable_node * current, syllable_node * root, int len,
		syllable_stack_tab * stack_table, syllable_prob_bundle * max_bundle) {
	if (current->child_size == 0 && !current->traversal
			&& current->path_len >= len) {
		current->traversal = true;
		//printf("\nBackword Prob [%s] %d %x", current->text, current->path_len,
		//		current);
		//printf("\n%d parent ", current->parent_size);

		leaf2root(current, root, stack_table);

		//route tree to calculate probability.
		syllable_prob_bundle * p_bundle = syllable_create_prob_bundle(
				SYLLABLE_PROB_SIZE);

		route2root(current, root, p_bundle, max_bundle);
		/* free prob bundle*/
		//if (tab_max != p_bundle) {
		//	free(p_bundle);
		//}
	}
	for (int i = 0; i < current->child_size; i++) {
		backwordConcat(current->child[i], root, len, stack_table, max_bundle);
	}
}
void out_of_pattern(char * text, syllable_stack * stack) {
	printf("\nOut-of-Patern : %s", text);
	printf("\nStack Len : %d", stack->sum_len);
	printf("\nFROM : %s", text + stack->sum_len);
	char tmp_text[1024] = "";
	strcpy(tmp_text, text + stack->sum_len);
	int is_front = tone_isFrontVowel(tmp_text, 0, strlen(tmp_text));
	int is_back = tone_isBackVowel(tmp_text, 0, strlen(tmp_text));
	int is_prev_front = tone_isFrontVowel(text, stack->sum_len - 6,
			strlen(text));
	printf("\nisFront = %d\nisBack = %d\nis_prev_front= %d", is_front, is_back,
			is_prev_front);
	int init_csn_index = 0;
	int init_csn_code = 04;
	int init_csn_len = 3;
	int change_index = 2;
	if (is_front != -1) {
		init_csn_index = 3;
		change_index = 5;
	} else if (is_back != -1 && is_prev_front != -1) {
		strcpy(tmp_text, text + stack->sum_len - 6); /* consider previous character */
		init_csn_index = 3;
		change_index = 5;
	} else if (is_back != -1) {
		strcpy(tmp_text, text + stack->sum_len - 3);
	}
	char init_char[20] = "";
	strncpy(init_char, tmp_text + init_csn_index, init_csn_len);
	init_char[init_csn_len] = '\0';
	printf("\ninit_consonant : [%d %d] %s", init_csn_index, init_csn_len,
			init_char);
	/* find sound of init_consonant*/
	Darts::DoubleArray::result_pair_type result_pair1[10];
	size_t init_csn_n = esan_da.commonPrefixSearch(init_char, result_pair1,
			sizeof(result_pair1));
	if (init_csn_n > 0) {
		printf("found : ");
		pronun_struct * pattern_st = pronun_struct_find(
				(int) result_pair1[0].value);
		printf("\nIC_Sound => ");
		if (pattern_st->st_unit > 0)
			init_csn_code = pattern_st->st[0]->st1 / 10000;
		//pronun_struct_print(pattern_st);
		//printf("\nCode = %d", init_csn_code);
	}

	signed char vbyte = (signed char) 0x81;
	int freq[100] = { 0 };
	pronun_struct * stru[100];
	int st_len[100] = { 0 };
	int st_c = 0;
	int num_max = 0;
	while (vbyte <= (signed char) 0xae) {
		tmp_text[change_index] = vbyte;
		printf("\n: %s", tmp_text);
		Darts::DoubleArray::result_pair_type result_pair[10];
		size_t num = esan_da.commonPrefixSearch(tmp_text, result_pair,
				sizeof(result_pair));
		if (num == 0) {
			//std::cout << tmp_text << ": not found" << std::endl;
		} else {
			for (size_t i = 0; i < num; i++) {
				std::cout << " " << result_pair[i].value << ":"
						<< (result_pair[i].length / 3);
				int n = (result_pair[i].length / 3);
				printf("LEN : %d", n);
				if (n >= 2) {
					freq[n]++;
					stru[st_c] = pronun_struct_find((int) result_pair[i].value);
					st_len[st_c] = n;
					if (n > num_max) {
						num_max = n;
					}
					st_c++;
				}
			}
		}

		vbyte++;
	}
	for (int i = 0; i < st_c; i++) {
		//pronun_struct_print(stru[i]);
	}
	for (int i = 0; i <= num_max; i++) {
		//printf("\nL=%d) %d ", i, freq[i]);
	}

	bool same_ic = true;
	bool same_v = true;
	bool same_fc = true;

	int d_ic = 0;
	int d_fc = 0;

	int old_i = 0;

	int freq_group_name[10] = { 0 };
	int freq_group_num[10] = { 0 };
	int max_g = 0;
	for (int i = 1; i < st_c; i++) {

		if (st_len[i] == num_max) {
			if (freq[num_max] == 1) {
				int mod_v = stru[i]->st[0]->st1 % 10000;
				if (max_g == 0) {
					freq_group_name[max_g] = mod_v;
					freq_group_num[max_g] = 1;
					max_g++;
				} else {
					bool flag = true;
					for (int k = 0; k < max_g; k++) {
						if (mod_v == freq_group_name[k]) {
							freq_group_num[k]++;
							flag = false;
							break;
						}
					}
					if (flag) {
						freq_group_name[max_g] = mod_v;
						freq_group_num[max_g] = 1;
						max_g++;
					}
				}
				break;
			}
			//pronun_struct_print(stru[i]);
			if (stru[old_i]->st[0]->st1 % 10000
					== stru[i]->st[0]->st1 % 10000) {
				printf("\n= %d", stru[i]->st[0]->st1 % 10000);
				int mod_v = stru[i]->st[0]->st1 % 10000;
				if (max_g == 0) {
					freq_group_name[max_g] = mod_v;
					freq_group_num[max_g] = 1;
					max_g++;
				} else {
					bool flag = true;
					for (int k = 0; k < max_g; k++) {
						if (mod_v == freq_group_name[k]) {
							freq_group_num[k]++;
							flag = false;
							break;
						}
					}
					if (flag) {
						freq_group_name[max_g] = mod_v;
						freq_group_num[max_g] = 1;
						max_g++;
					}
				}
				d_fc++;
			}
			if (stru[old_i]->st[0]->st1 / 10000
					== stru[i]->st[0]->st1 / 10000) {
				d_ic++;
			}
			old_i = i;
		}
	}

	printf("\nd_ic = %d d_fc = %d", d_ic, d_fc);
	if (d_ic > d_fc) {
		printf("\nPredict : ?-vowel-final_c");
	}
	printf("\n#GROUP");
	for (int i = 0; i < max_g; i++) {
		printf("\nG%d %d\t%d", i + 1, freq_group_name[i], freq_group_num[i]);
	}
	/*find inint consonant */
}
void buildTree(char * text, int start, char * re, syllable_node * current_node,
		syllable_stack * stack) {
	int text_len = strlen(text);
	//strcpy(cmp, "");
	char tmp[1024];
	int k = 0;
	int skip_len = 0;
	int skip_tone = 0;
	/*for(int k=2;k<text_len;k=k+3){
	 int sk = skip(text,k);
	 if (sk>0)
	 skip_tone = sk;
	 if(sk==-1 && k>5){
	 skip_len = k-3;
	 break;
	 }

	 }*/
	//printf("\nskip %d %d %s",skip_len,skip_tone,text);
	Darts::DoubleArray::result_pair_type result_pair[10];

	size_t num = esan_da.commonPrefixSearch(text, result_pair,
			sizeof(result_pair));

	printf("\n");
	if (num == 0) {
		std::cout << text << ": not found" << std::endl;
	} else {

		// std::cout << text << ": found, num=" << num << " ";
		for (size_t i = 0; i < num; ++i) {
			//char * cmp = (char *) calloc(256, sizeof(char));
			//strcpy(cmp, "");
			//strcpy(cmp, re);
			//std::cout << " " << result_pair[i].value << ":"
			//		<< result_pair[i].length;
			char cut[40] = "";

			strcpy(tmp, text + result_pair[i].length);
			strncpy(cut, text, (int) result_pair[i].length);

			//strcat(cmp, "|");
			//strcat(cmp, cut);
			//printf("\n%d=>%s %d:%d", i, cmp, result_pair[i].value,
			//		result_pair[i].length);
			syllable_node * new_node = syllable_tree_create_node(cut);
			new_node->text_len = (int) result_pair[i].length;

			pronun_struct * pos = pronun_struct_find(
					(int) result_pair[i].value);
			printf("\nFound %s %d", new_node->text, (int) result_pair[i].value);
			new_node->struc = pos;
			//pronun_struct_print(pos);
			syllable_tree_add_child(current_node, new_node);

			//free(cmp);
			//find tree in stack
			syllable_node * loop_tree = syllable_stack_find(stack,
					current_node->path_len + new_node->text_len);

			new_node->path_len = new_node->parent[0]->path_len
					+ new_node->text_len;

			syllable_stack_push(stack, new_node);

			if (loop_tree == NULL) {

				buildTree(tmp, (int) result_pair[i].length, re, new_node,
						stack);

			} else {
				//printf("found [%p %s] Copy Tree.", loop_tree, loop_tree->text);
				/*update path lenght*/
				new_node->child_size = loop_tree->child_size;
				for (int i = 0; i < loop_tree->child_size; i++) {
					if (stack->sum_len < loop_tree->child[i]->path_len) {
						stack->sum_len = loop_tree->child[i]->path_len;
						//printf("\nup path = %d", stack->sum_len);
					}
					new_node->child[i] = loop_tree->child[i];
					//printf("\ncopy %s", loop_tree->child[i]->text);
					syllable_tree_add_parent(new_node, loop_tree->child[i]);
				}
			}

		}
		std::cout << std::endl;
	}
}

/*
 * free all variable for the new word.
 */
void free_to_root(syllable_node * node) {
	if (node != NULL) {
		for (int i = 0; i < node->parent_size; i++) {
			free_to_root(node->parent[i]);
		}
		if (node->prob_tab != NULL)
			free(node->prob_tab);
		free(node);
	}
}

char * text2phoneme(char * text) {
	char * phoneme = (char *) calloc(1024, sizeof(char));
	int len = strlen(text);
	char buffer[1024] = "";
	/* create root tree node */
	syllable_node * root = NULL;
	root = syllable_tree_create_node("Root");
	root->path_len = 0;
	root->child_size = 0;
	/* create prob table  stack */
	syllable_stack_tab * stack_table = syllable_create_stack_prob_table(100);
	/* create node stack */
	syllable_stack * stack = syllable_stack_create();

	clock_t start = clock();

	/* create syllable_prob_bundle for keep a max probability */
	syllable_prob_bundle max_bundle;
	max_bundle.size = 0;
	/* create a tree of input text*/
	buildTree(text, 0, buffer, root, stack);
	//syllable_stack_print(stack);
	//printf("\n[ %d:%d ]", stack->sum_len, len);
	if (stack->sum_len < len) {
		//out_of_pattern(text, stack);
		free(phoneme);
		return NULL;
	}

	/* calculate probabilty from leaf to root node*/
	backwordConcat(root, root, strlen(text), stack_table, &max_bundle);
	/* get an output phoneme */
//#define PHONE_CODE 1
#ifdef PHONE_CODE
	syllable_prob_bundle2phoneme_code(&max_bundle, phoneme);
	strcat(phoneme,"\t");
	strcat(phoneme,text);
	strcat(phoneme,"\n");
#else
	//syllable_prob_bundle2phoneme(&max_bundle, phoneme);
	//syllable_prob_bundle2phoneme_tone_analysis(&max_bundle, phoneme);
#endif
	syllable_prob_bundle_print(&max_bundle, stdout);
	/* free a stack and all node*/
	syllable_stack_clear(stack);
	/* free a probability of all node */
	syllable_free_stack_prob_table(stack_table);

	/* free root node*/
	if (root->text != NULL) {
		free(root->text);
	}
	free(root);
	double ta_time = ((double) clock() - start) / CLOCKS_PER_SEC;
	printf("\nText2Phoneme Time : %.4f sec", ta_time);
	return phoneme;
}
bool g2p_dsearch(char * text, syllable_seq * seq, int wnum) {
#ifdef ENABLED_DICTIONATY
#ifdef DEBUG_ENABLED
	ESTS_ENTER("\nSEARCH-DICTIONRY :");
#endif
	//found this word in dictionary and push it to sequence.
	pronun_phone * phone = Dict_Esan_Search(text);
	//printf("\n%s\t%p", text, phone);
	if (phone != NULL) {
#ifdef DEBUG_ENABLED
		ESTS_SHOW("\tFound (OK)", phone);
#endif
		for (int i = 0; i < phone->n_syl; i++) {
			syllable_seq_unit * unit = (syllable_seq_unit *) malloc(
					sizeof(syllable_seq_unit));
			unit->sylcode = phone->phone[i] / 10;
			unit->tone = phone->phone[i] % 10;
			unit->wdnum = wnum;
			unit->c = -1;
			unit->mt = -1;
			unit->wt = -1;
			unit->src = 'D';
			seq->seq[seq->size++] = unit;

		}
		return true;
	} else {
#ifdef DEBUG_ENABLED
		ESTS_SHOW("\tNot Found !", text);
#endif
		return false;
	}
#endif
}
bool g2p_syllable_map(char * text, syllable_seq * seq, int wnum) {
#ifdef ENABLED_SYL_MAPPING

#ifdef DEBUG_ENABLED
	ESTS_ENTER("\nSYLLABLE-MAPPING :");
#endif
	syllable_seq_unit * unit = sylmap_map(text, wnum);
	if (unit != NULL) {
#ifdef DEBUG_ENABLED
		ESTS_ENTER("\tFound Pattern.");
#endif
		seq->seq[seq->size++] = unit;
		return true;
	} else {
#ifdef DEBUG_ENABLED
		ESTS_ENTER("\tUnknown Pattern.");
#endif
		return false;
	}

#endif
}

int g2p_syllable_auto(char * text, syllable_seq * seq, int wnum) {

}
#define SYL_SEQ_SIZE 512
int text2sylseq(char * text, syllable_seq * seq, int wnum,int * fxn) {
#ifdef DEBUG_ENABLED
	ESTS_SHOW("\n========================\nWORD :\t%s", text);
#endif
	bool found = false;

	found = g2p_dsearch(text, seq, *fxn); // find in dict

	/* remove karan */
	int wlen = strlen(text);
	char _tmp1[512] = "";
	char _tmp2[512] = "";
	signed char karan1 = (signed char) (0xb9);
	signed char karan2 = (signed char) (0x8c);
	int c_i = 0;
	for (int i = 0; i < wlen; i = i + 3) {
		if (text[i + 1] == karan1 && text[i + 2] == karan2) {
			//strcpy(_tmp2,_tmp1);
			c_i -= 3;
			if(tone_isBackVowel(text,c_i,wlen)!=-1){
				printf("\n%s is BackVowel",text+c_i,wlen);
				c_i -= 3;
			}
			_tmp1[c_i] = '\0';
		} else {
			_tmp1[c_i] = text[i];
			_tmp1[c_i + 1] = text[i + 1];
			_tmp1[c_i + 2] = text[i + 2];
			_tmp1[c_i + 3] = '\0';
			c_i += 3;
		}
	}
	printf("\nTMP = %s", _tmp1);
	strcpy(text, _tmp1);

	if (!found)
		found = g2p_syllable_map(text, seq, *fxn); //pattern mapping

	if (!found) {
#ifdef DEBUG_ENABLED
		ESTS_ENTER("\tAuto Syllable Pattern.");
#endif
		int len = strlen(text);
		char buffer[1024] = "";
		/* create root tree node */
		syllable_node * root = NULL;
		root = syllable_tree_create_node("Root");
		/* create prob table  stack */
		syllable_stack_tab * stack_table = syllable_create_stack_prob_table(
				100);
		/* create node stack */
		syllable_stack * stack = syllable_stack_create();

		clock_t start = clock();

		/* create syllable_prob_bundle for keep a max probability */
		syllable_prob_bundle max_bundle;
		max_bundle.size = 0;
		/* create a tree of input text*/
		buildTree(text, 0, buffer, root, stack);
		//syllable_stack_print(stack);
		//printf("\n[ %d:%d ]", stack->sum_len, len);
		if (stack->sum_len < len) {
			//out_of_pattern(text, stack);

			char syl_seg[512]="";
			int r = sx_extract(text,syl_seg,stack->sum_len,len);


			printf("\nUNK : %s (%d)",syl_seg,r);
			char * phone = NULL;
			if(r!=-1){
				phone = test_sequence(syl_seg,seq,fxn);
				*fxn = *fxn-1; //
			}

			if(phone!=NULL) free(phone);
			syllable_stack_clear(stack);
			syllable_free_stack_prob_table(stack_table);
			if (root->text != NULL) {
				free(root->text);
			}
			free(root);

			printf("\n=====END OOP=====");
			return 1;

		}

		/* calculate probabilty from leaf to root node*/
		backwordConcat(root, root, strlen(text), stack_table, &max_bundle);
		/* get an output phoneme */
		syllable_prob_bundle2sylseq(&max_bundle, seq, *fxn);
		//syllable_prob_bundle2phoneme_tone_analysis(&max_bundle, seq);

		syllable_prob_bundle_print(&max_bundle, stdout);
		/* free a stack and all node*/
		syllable_stack_clear(stack);
		/* free a probability of all node */
		syllable_free_stack_prob_table(stack_table);

		/* free root node*/
		if (root->text != NULL) {
			free(root->text);
		}
		free(root);
		double ta_time = ((double) clock() - start) / CLOCKS_PER_SEC;
		printf("\nText2Phoneme Time : %.4f sec", ta_time);

		return 1;
	}

}
char * test_sequence(char * txt, syllable_seq * seq,int * fxn) {

	printf("\nTest_SQ %s", txt);
	int number = 0;
	char tmp[1024] = "";
	char token_tmp[500][500] ;
	int  token_n =0;
	strcpy(tmp, txt);
	char * token = strtok(tmp, "|");
	int check_num[512] = { 0 };
	int check_cursor = 0;
	while (token) {
		if(token==NULL)break;
		char tmp2[512] = "";
		strcpy(tmp2, token);
		strcpy(token_tmp[token_n++],tmp2);
		token = strtok(NULL, "|");
	}

	for(int i=0;i<token_n;i++){
				if (strlen(token_tmp[i]) > 0 && strcmp(" ",token_tmp[i])!=0 ) {
					int r = text2sylseq(token_tmp[i], seq,number, fxn);
					//check not recog
					*fxn =*fxn+1;
					check_num[check_cursor++] = r;
					number++;
				}
	}
	char * phoneme = NULL;
	if (seq->size == 0)
		return NULL;

	syllable_prob_sylseq_predict_tone(seq);
	syllable_seq_print(seq);
	printf("\n===============================");
	phoneme = (char *) calloc(1024, sizeof(char));
	strcpy(phoneme, "");
	int old = -1;

	for (int i = 0; i < seq->size; i++) {
		char tmp[512] = "x";
		pronun_sturct_num2phone((char *) tmp, seq->seq[i]->sylcode,
				seq->seq[i]->tone);
		printf("\n%s", tmp);
		strcat(tmp, "|");
		strcat(phoneme, "");
		strcat(phoneme, tmp);
		if (i == seq->size - 1) {
			strcat(phoneme, "*");
		} else if (seq->seq[i]->wdnum != seq->seq[i + 1]->wdnum) {
#ifdef ENABLED_SHOW_UNKNOWN_PHONE
			if (seq->seq[i + 1]->wdnum - seq->seq[i]->wdnum > 1) {
				strcat(phoneme, "*-UNK-|");
			}
#endif
			strcat(phoneme, "*");
		}

		old = seq->seq[i]->wdnum;
	}
	printf("\n%s", phoneme);
	return phoneme;
}

int test_dict(char * file, char * out) {
	FILE * fp = fopen(file, "r");
	FILE * fw = fopen(out, "w");
	char unknown[500] = "";
	strcpy(unknown, out);
	strcat(unknown, ".unknown");
	FILE * fun = fopen(unknown, "w");
	char line[500] = "";
	char cont[500] = "";
	int dict_num = 0;
	int syll_num = 0;
	int n = 1;
	int un = 0;
	int word = 0;
	clock_t start = clock();
	char oneword[500];
	char *c;

	while (!feof(fp)) {
		strcpy(line, "");
		fscanf(fp, "%s\n", oneword);
		//c = fgets(oneword, 500, fp); /* get one line from the file */
		printf("%s\n", oneword); /* display it on the monitor  */
		//char * token = strtok(oneword, "\t");
		strcpy(line, oneword);
		//printf("%s",line);

		/*
		 token = strtok(NULL, "\t");
		 strcpy(cont,token);
		 token = strtok(NULL, "\t");
		 dict_num = atoi(token);
		 token = strtok(NULL, "\t");
		 syll_num = atoi(token);
		 */
		//printf("#%s\t#%s\t#%d\t#%d\n",line,cont,dict_num,syll_num);
		char tmp_line[500] = "";

		int result = 0;

		strcpy(tmp_line, line);

		//test
		syllable_seq * seq = syllable_seq_create(SYL_SEQ_SIZE);
		char * p = test_sequence(tmp_line, seq,0);

		result = seq->size - syll_num;

		printf("%s\t%d", p, result);
		//if (found)
		//fprintf(fun, "\n");
		fprintf(fw, "\n%s\t%s\t%s", tmp_line, seq->wseg, p);
		if (p != NULL) {
			free(p);
		}
		syllable_seq_free(seq);
		n++;
		//if (n == 20)
		//	break;

	}
	printf("\nTest\t%d sentences.\nTest\t%d words.", n, word);
	double ta_time = ((double) clock() - start) / CLOCKS_PER_SEC;
	printf("\nTest Time : %f sec", ta_time);
	fclose(fp);
	fclose(fw);
	fclose(fun);
}
int test_sequeence_fn(char * in_file, char * out_file) {
	printf("\nG2P TEST Sequence");
	printf("\nInput File : %s", in_file);
	printf("\nOutput File : %s", out_file);
	FILE * fp = fopen(in_file, "r");
	FILE * fw = fopen(out_file, "w");
	int c = 0;
	char line[500] = "";
	while (!feof(fp)) {

		strcpy(line, "");
		fscanf(fp, "%s\n", line);
		//start with $
		if (line[0] == '$') {
			int  wnum = 0;
			int * twnum = &wnum;
			syllable_seq * seq = syllable_seq_create(SYL_SEQ_SIZE);
			char * p = test_sequence(line + 1, seq,twnum);
			//write phoneme to file
			//printf("\n$%s\n@%s",line+1, p);
			fprintf(fw, "%s\t%s\n", line + 1, p);
			c++;
			syllable_seq_free(seq);
			if (p != NULL) {
				free(p);
			}
		}
	}
	printf("\n%d sentences.", c);
	fclose(fp);
	fclose(fw);
	return 0;
}
int descLen(char * text, int dec_size, int wsize) {
	char tmp[512] = "";
	strncpy(tmp, text, wsize - dec_size);
	tmp[wsize - dec_size] = '\0';
	strcpy(text, tmp);
}
int removeToneMarker(char * text, int wsize) {
	char tmp[512] = "";
	int c = 0;
	for (int i = 0; i < wsize; i = i + 3) {
		if (!tone_isToneSymbol(text, i, wsize)) {
			tmp[c] = text[i];
			tmp[c + 1] = text[i + 1];
			tmp[c + 2] = text[i + 2];
			c = c + 3;
		}
	}
	tmp[c] = '\0';
	//printf("\n%s",tmp);
	strcpy(text, tmp);
}
int compareSourceWord(char * src, char * tmp, int len) {
	for (int i = 0; i < len; i++) {
		if (src[i] != tmp[i]) {
			return i - 2;
		}
	}
	return -1;
}
int findOutOffPattern(pronun_struct_unit * new_unit, char * text) {
	char tmp_text[512] = "";
	strcpy(tmp_text, text);
	int len = strlen(tmp_text);
	/*modify consonant and check frequency*/
	int current_size = 0;
	int max_len = -99999;
	pronun_struct * select_template = NULL;
	for (int i = 0; i < len; i = i + 3) {
		int r = tone_isCharSymbol(tmp_text, i, strlen(tmp_text));
		printf("\n%s\t%d", tmp_text + i, r);
		signed char vbyte = (signed char) 0x81;
		if (r) {
			while (vbyte <= (signed char) 0xae) {
				char tmp_word[512];
				strcpy(tmp_word, tmp_text);
				removeToneMarker((char *) tmp_word, len);
				len = strlen(tmp_word);
				if (len <= max_len)
					break; //break when length equal max
				tmp_word[i + 2] = vbyte;
				for (int h = 0; h < len; h = h + 3) {
					int index = 0;

					esan_da.exactMatchSearch(tmp_word, index);
					if (index != -1) {
						printf("\n%s %s\t%d", tmp_text, tmp_word, index);
						int pos = 0;
						int clen = strlen(tmp_word);
						if (clen <= max_len)
							break; //break when length equal max
						pronun_struct * st = pronun_struct_find(index);
						int effect_pos = 0;
						int effect_type = 0; // 0 = no effect; 1 = modify init; 2 = modify final
						for (int i = 0; i < clen; i = i + 3) {
							//pos = compareSourceWord(tmp_text,tmp_word,len);
							printf("\nx = %s %s %d %d", tmp_word + i,
									tmp_text + i, tmp_text[i + 2],
									tmp_word[i + 2]);
							//compare first char
							if (tmp_text[i + 2] == tmp_word[i + 2]
									&& tmp_text[i + 1] == tmp_word[i + 1]) {
								printf("\n%s eq %s", tmp_text + i,
										tmp_word + i);
							} else {
								printf("\neffect char.");
								effect_pos = i;
								printf("\n%s !eq %s", tmp_text + i,
										tmp_word + i);

								int ci = cmatch_getInitConsoCode(
										tmp_word[i + 2]);
								int cf = cmatch_getFinalConsoCode(
										tmp_word[i + 2]);
								int mci = st->st[0]->st1 / 10000;
								int mcf = st->st[0]->st1 % 100;

								printf("\npos = %d\t%s\t[%d %d]--> %d", pos,
										tmp_word + pos, ci, cf, st->st[0]->st1);
								printf("\n[%d %d]\t[%d %d]", ci, cf, mci, mcf);
								if (ci == mci) {
									printf("\n eq init conso.");
									effect_type = 1;
								}
								if (cf == mcf) {
									printf("\n eq final conso.");
									effect_type = 2;
								}
								select_template = st;

							}
						}
						printf("\neffect_pos = %d type=%d", effect_pos,
								effect_type);
						//modify phone
						printf("\n%s --> %s", tmp_text, tmp_text + effect_pos);
						int code = -1;
						int new_code = 0;
						if (effect_type == 1) {
							//
							int src_code = select_template->st[0]->st1 % 10000;
							code = cmatch_getInitConsoCode(
									tmp_text[effect_pos + 2]);
							new_code = code * 10000 + src_code;
						} else if (effect_type == 2) {
							//
							int src_code = select_template->st[0]->st1 / 100;
							code = cmatch_getFinalConsoCode(
									tmp_text[effect_pos + 2]);
							new_code = src_code * 100 + code;

						} else if (effect_type == 0) {
							int src_code = select_template->st[0]->st1;
							new_code = src_code;
						}
						printf("\nST = %p Code = %d\nResult = %06d",
								select_template, code, new_code);
						new_unit->st1 = new_code;
						new_unit->sound = 1;

						max_len = len - h;
						break;
					}

					//printf("\n%s\t%d", tmp_word, index);
					descLen((char *) tmp_word, 3, len - h);

				}
				vbyte++;
			}
			printf("\nMAX = %d", max_len);
		}
	}
	return max_len;
}
int findInitConson(char * text) {
	int text_len = strlen(text);
	int sum_len = 0;
	int tone_tk_table[200];
	int text_len_table[200];
	int rm_sum_len = 0;
	int rm_index = 0;
	for (int i = 0; i < text_len / 3; i++) {
		tone_tk_table[i] = tone_toneSymbol(text, i * 3, text_len);
		//rm_sum_len++;
		if (tone_tk_table[i] != 0)
			rm_sum_len += 1;
		text_len_table[i] = ++rm_sum_len;
	}
	printf("Tone Marker Table.");
	for (int i = 0; i < text_len / 3; i++) {
		printf("\n%d %d", tone_tk_table[i], text_len_table[i]);
	}
	char tmp_rm_tone[512] = "";
	strcpy(tmp_rm_tone, text);
	removeToneMarker((char *) tmp_rm_tone, text_len);
	int remove_tone_len = strlen(tmp_rm_tone);
	while (sum_len < remove_tone_len) {
		pronun_struct_unit * new_unit = (pronun_struct_unit *) malloc(
				sizeof(pronun_struct_unit));
		int longest = findOutOffPattern(new_unit, tmp_rm_tone + sum_len);

		printf("\nLONGEST %d  unit-> %d", longest, new_unit->st1);
		//find tone maker an init consonant group
		printf("\nFind tone marker. from %d -- %d ", sum_len,
				sum_len + longest);
		int start_i = sum_len / 3;
		int end_i = (sum_len + longest) / 3;
		for (int j = start_i; j < end_i; j++) {
			printf("\n%d %d", tone_tk_table[j], text_len_table[j]);
		}
		sum_len += longest;
	}
}
int findFinalConson(char * text) {
	return 0;
}
int main() {
	printf("\nAutomatic syllable Pattern");
	Dict_Load_Index("/home/think/dictNew/pro/g2p_data/binary/tree.ind",
			&esan_da);
	pronun_struct_load_binary(
			"/home/think/dictNew/pro/g2p_data/binary/tree.bin");
	ngram_dict_load("/home/think/dictNew/pro/g2p_data/binary/prob.ind");
	ngram_load("/home/think/dictNew/pro/g2p_data/binary/prob.bin");

//test load tone predict path.
	tone_ngram_prob_load_bin(
			"/home/think/dict/dict_train_tone/bin/tone_prob.bin");
	tone_ngram_prob_load_dict(
			"/home/think/dict/dict_train_tone/bin/tone_prob.ind");
	tone_ngram_pattern_load_bin(
			"/home/think/dict/dict_train_tone/bin/tone_st.bin");
	tone_ngram_pattern_load_dict(
			"/home/think/dict/dict_train_tone/bin/tone_st.ind");
//char temp[512] = "กาก่าก้าก๊าก๋า";

	Dict_Esan_Load("/home/think/dictNew/pro/wlist.ind",
			"/home/think/dictNew/pro/phone.bin");

	ws_segment_load("/home/think/CRF++-0.58/example/seg/model");

//test_sequeence_fn("/home/think/test_text/test_source.txt","/home/think/test_text/test_out.txt");
	//test_dict("/home/think/test_text/test_source.txt","/home/think/test_text/test_source_out.txt");


//	char * sentence = "แท้เดอาจารย์จเขมจิตต์เอยญาติโยมเอ้ยอย่าแตกแยกกันเด้อสงสารพ่อแน่";
//	char * out = ws_segment_tokken(sentence);
//	printf("\nout : %s", out);
//while(true){
	char * sentence = "หลาย";
		char  * out  = ws_segment_tokken(sentence);
	syllable_seq * seq = syllable_seq_create(SYL_SEQ_SIZE);
	int  wnum = 0;
	int * twnum = &wnum;
	char * phoneme = test_sequence(out, seq,twnum);
#ifdef DEBUG_ENABLED
	ESTS_SHOW("\nOutput-Phoneme : %s", phoneme);
#endif
	syllable_seq_free(seq);
	if (phoneme != NULL)
		free(phoneme);

	//free(out);
	//char * text = "เลิ้ศ";
	//findInitConson(text);

//}

//printf("\n%s", p);
//printf("i = %d",i);
	/*
	 for (int i = 0; i < 10; i++) {
	 char * temp = (char *) calloc(256, sizeof(char));
	 strcpy(temp, "ฮอดบ้าน");
	 char * phoneme = text2phoneme(temp);
	 printf("%s",phoneme);
	 if(phoneme!=NULL) free(phoneme);

	 }*/

	printf("\nEND:");
	return 0;
}

